package breaker

import (
	"errors"
	"sync"
	"sync/atomic"
	"time"
)

// 熔断器状态常量
const (
	StateClosedStr   = "关闭"  // 关闭状态，允许请求通过
	StateOpenStr     = "开启"  // 开启状态，请求被熔断
	StateHalfOpenStr = "半开启" // 半开状态，允许部分请求通过以探测服务是否恢复
)

// 错误定义
var (
	ErrFallback = errors.New("服务降级，使用备用方案")
)

// AdvancedBreaker 高级熔断器
type AdvancedBreaker struct {
	MetricsBreaker                         // 嵌入基础熔断器
	fallbackFuncs  map[string]FallbackFunc // 降级函数映射
	fallbackMutex  sync.RWMutex            // 降级函数映射的锁
	isOpen         int32                   // 熔断器是否开启，使用原子操作
}

// NewAdvancedBreaker 创建高级熔断器
func NewAdvancedBreaker(errorRate float64, windowSize int, timeoutDuration time.Duration) *AdvancedBreaker {
	return &AdvancedBreaker{
		MetricsBreaker: *NewMetricsBreaker(errorRate, windowSize, timeoutDuration),
		fallbackFuncs:  make(map[string]FallbackFunc),
		isOpen:         0,
	}
}

// ExecuteWithFallback 执行请求，如果熔断器开启则使用降级函数
func (ab *AdvancedBreaker) ExecuteWithFallback(key string, fn func() error) error {
	// 检查熔断器状态
	if atomic.LoadInt32(&ab.isOpen) == 1 && ab.GetState() == StateOpen {
		// 熔断器开启，返回降级错误
		return ErrFallback
	}

	// 执行请求
	err := ab.Execute(fn)

	// 更新熔断器状态标志
	if ab.GetState() == StateOpen {
		atomic.StoreInt32(&ab.isOpen, 1)
	} else {
		atomic.StoreInt32(&ab.isOpen, 0)
	}

	return err
}

// ExecuteWithResult 执行有返回值的请求，支持降级
func (ab *AdvancedBreaker) ExecuteWithResult(key string, fn func() (interface{}, error)) (interface{}, error) {
	// 检查熔断器状态
	if atomic.LoadInt32(&ab.isOpen) == 1 && ab.GetState() == StateOpen {
		// 熔断器开启，使用降级函数
		return ab.fallback(key, ErrCircuitOpen)
	}

	// 执行请求
	result, err := fn()

	// 更新熔断器状态
	ab.mutex.Lock()
	if err != nil {
		// 请求失败
		ab.onFailure()
		// 如果熔断器开启，使用降级函数
		if ab.state == StateOpen {
			atomic.StoreInt32(&ab.isOpen, 1)
			ab.mutex.Unlock()
			return ab.fallback(key, err)
		}
	} else {
		// 请求成功
		ab.onSuccess()
		if ab.state != StateOpen {
			atomic.StoreInt32(&ab.isOpen, 0)
		}
	}
	ab.mutex.Unlock()

	return result, err
}

// RegisterFallback 注册降级函数
func (ab *AdvancedBreaker) RegisterFallback(key string, fallbackFunc FallbackFunc) {
	ab.fallbackMutex.Lock()
	defer ab.fallbackMutex.Unlock()

	ab.fallbackFuncs[key] = fallbackFunc
}

// fallback 执行降级函数
func (ab *AdvancedBreaker) fallback(key string, err error) (interface{}, error) {
	ab.fallbackMutex.RLock()
	fallbackFunc, ok := ab.fallbackFuncs[key]
	ab.fallbackMutex.RUnlock()

	if !ok {
		// 没有找到对应的降级函数，返回原始错误
		return nil, err
	}

	// 执行降级函数
	return fallbackFunc(err)
}

// GetStateDescription 获取熔断器状态描述
func (ab *AdvancedBreaker) GetStateDescription() string {
	switch ab.GetState() {
	case StateClosed:
		return StateClosedStr
	case StateOpen:
		return StateOpenStr
	case StateHalfOpen:
		return StateHalfOpenStr
	default:
		return "未知状态"
	}
}

// BreakerManager 熔断器管理器
type BreakerManager struct {
	breakers      map[string]*AdvancedBreaker // 熔断器映射
	breakersMutex sync.RWMutex                // 熔断器映射的锁
}

// NewBreakerManager 创建熔断器管理器
func NewBreakerManager() *BreakerManager {
	return &BreakerManager{
		breakers: make(map[string]*AdvancedBreaker),
	}
}

// GetBreaker 获取指定服务的熔断器，如果不存在则创建
func (bm *BreakerManager) GetBreaker(service string) *AdvancedBreaker {
	bm.breakersMutex.RLock()
	breaker, ok := bm.breakers[service]
	bm.breakersMutex.RUnlock()

	if ok {
		return breaker
	}

	// 创建新的熔断器
	bm.breakersMutex.Lock()
	defer bm.breakersMutex.Unlock()

	// 再次检查，避免并发创建
	breaker, ok = bm.breakers[service]
	if ok {
		return breaker
	}

	// 默认配置：50%错误率触发熔断，统计窗口大小100，熔断时间30秒
	breaker = NewAdvancedBreaker(0.5, 100, 30*time.Second)
	bm.breakers[service] = breaker
	return breaker
}

// ResetBreaker 重置指定服务的熔断器
func (bm *BreakerManager) ResetBreaker(service string) {
	bm.breakersMutex.RLock()
	breaker, ok := bm.breakers[service]
	bm.breakersMutex.RUnlock()

	if ok {
		breaker.Reset()
	}
}

// GetAllBreakerStatus 获取所有熔断器状态
func (bm *BreakerManager) GetAllBreakerStatus() map[string]string {
	bm.breakersMutex.RLock()
	defer bm.breakersMutex.RUnlock()

	result := make(map[string]string)
	for service, breaker := range bm.breakers {
		result[service] = breaker.GetStateDescription()
	}

	return result
}
